package Agents;

import java.awt.Color;

import Helpers.Common;
import Model.SimModel;
import Param.Constants;
import sim.engine.SimState;
import sim.portrayal.simple.RectanglePortrayal2D;
import sim.util.Bag;
import sim.util.Int2D;

@SuppressWarnings("serial")
public class Zombie extends Entity 
{
	enum Interest{
		Default,
		H,
		C
	}
	
	/**
	 * Carré sous-jacent pour "dinner"
	 */
	protected RectanglePortrayal2D rectDinner = new RectanglePortrayal2D(new Color(0, 205, 0, 255));

	public Zombie(SimModel m, Int2D position) {
		super(m, position);

		// Initialisation de la couleur de l'agent
		this.paint = Color.red;
		this.life = Constants.ZOMBIE_MAX_LIFE;
	}

	/**
	 * Algorithme général
	 */
	@Override
	public void step(SimState state) 
	{
		int x = this.getPos().x;
		int y = this.getPos().y;
		
		// On supprime les éventuels rectangles
		Common.removeRectangles(this.model.yard, x, y);
		Bag elementsNextTo = this.detectAdjacent();
		//on enlève tous les zombies et rectangles des resultats
		for(int i=0 ; i<elementsNextTo.size() ; i++){
			if(elementsNextTo.get(i) instanceof Zombie || elementsNextTo.get(i) instanceof RectanglePortrayal2D){
				elementsNextTo.remove(i);
				i--;
			}
		}
		// Ne détecte rien d'intéressant sur les cases adjacentes
		if (elementsNextTo.isEmpty()) {
			Bag elementsInPerception = detectInPerception();
			//on enlève tous les zombies et rectangles des resultats
			for(int i=0 ; i<elementsInPerception.size() ; i++){
				if(elementsInPerception.get(i) instanceof Zombie || elementsInPerception.get(i) instanceof RectanglePortrayal2D){
					elementsInPerception.remove(i);
					i--;
				}
			}
			// Ne détecte rien dans la zone de perception
			if (elementsInPerception.isEmpty()) {
				roam();
			} else {
				// Détecte dans la zone de perception
				moveToInterest(elementsInPerception);
			}
		} else {
			// Détecte sur les cases adjacentes
			Corpse corpse = Common.getCorpse(elementsNextTo);
			if (corpse != null){
				eatCorpse(corpse);
				// Colorer les cases pour le repas
				displayRectDinner();
				corpse.displayRectDinner();
			} else {
				Human human = Common.getWeakestHuman(elementsNextTo);
				if(human != null){
					boolean hit = attack(human);
					displayRectAttack();
					if(hit) {
						human.getVirus().contaminate();
					}
				}
			}
		}
		survive();
	}

	protected void displayRectDinner()
	{
		rectDinner.filled = false;
		this.model.yard.setObjectLocation(rectDinner, this.getPos());
	}
	
	/**
	 * Errer (deplacement aleatoire)
	 */
	private void roam() {
		int x, y;
		int moveSpeed = Constants.ZOMBIE_MOVESPEED;
		int deltax = Common.getRandom(-moveSpeed, moveSpeed);
		int deltay = Common.getRandom(-moveSpeed, moveSpeed);
		if(deltax != 0 && deltay != 0){
			x = position.x + deltax;
			y = position.y + deltay;
			move(getAllowedMovement(new Int2D(x,y)).position);
		}
	}

	private void moveToInterest(Bag elements) {
		int perception = Constants.ZOMBIE_PERCEPTION;
		
		//les zombies ont déjà été retirés de éléments
		Movement interest = new Movement(new Int2D(-1,-1),perception,perception);
		Movement tmpInterest = interest;
		Interest interest_class = Interest.Default; //classe de l'interet (C ou H)
		for(int i = 0; i<elements.size() ; i++){
			if(elements.get(i) instanceof Corpse){
				tmpInterest = getAllowedMovement(((Corpse)elements.get(i)).getPos());
				if(interest_class==Interest.C && tmpInterest.distStart < interest.distStart && tmpInterest.distTarget<=interest.distTarget){
					interest = tmpInterest;
					interest_class=Interest.C;
				}
				else if(interest_class!=Interest.C && (interest.distTarget!=0 || tmpInterest.distTarget==0)){
					interest = tmpInterest;
					interest_class=Interest.C;
				}
			}
			else if(elements.get(i) instanceof Human && (interest_class!=Interest.C || interest.distTarget>0)){
				tmpInterest = getAllowedMovement(((Human)elements.get(i)).getPos());
				if(interest_class!=Interest.C && tmpInterest.distStart < interest.distStart && tmpInterest.distTarget<=interest.distTarget){
					interest = tmpInterest;
					interest_class=Interest.H;
				}
				else if(interest_class==Interest.C && tmpInterest.distTarget==0){
					interest = tmpInterest;
					interest_class=Interest.C;
				}
			}
		}
		move(interest.position);
	}
	
	private void eatCorpse(Corpse corpse) 
	{
		int updatedLife = life + corpse.beEaten();
		life = updatedLife < Constants.ZOMBIE_MAX_LIFE ? updatedLife : Constants.ZOMBIE_MAX_LIFE;
	}

	protected void die() 
	{
		int x = this.getPos().x;
		int y = this.getPos().y;
		
		//System.out.println("Mort du zombie");
		
		model.deleteZombie();
		model.yard.remove(this);
		Common.removeRectangles(this.model.yard, x, y);
		//System.out.println("je meurs (zombie)");
		stoppable.stop();
	}
}
